#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#include <imp/imp_log.h>
#include <protobuf-c/NCU_Params.proto-c.pb-c.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#define TAG							"NCU"
#define NCU_DBG_ENABLE_FILE			"/tmp/ncu_dbg"
#define NCU_DBG_CONFIG_FILE			"/tmp/nd.bin"
#define NCU_DBG_TRIGGER_FILE		"/tmp/ncu_trig"
#define NCU_CONFIG_FILE_PATH_PREFIX		"/etc/sensor/"
#define TMP_BUF_SIZE				(4 * 1024)

//#define NCU_PARAMS_DEBUG

static NCUParams *g_ncu_params_p = NULL;
static bool g_debug_mode_en = false;
static bool g_ncu_availiable = false;
static bool g_force_trig = false;
static int g_last_total_gain = 0;

NCUParams *get_ncu_params(void)
{
	if (g_ncu_availiable)
		return g_ncu_params_p;
	else
		return NULL;
}

static bool dbg_is_triggered(void)
{
	return (access(NCU_DBG_TRIGGER_FILE, F_OK) == 0) || (g_force_trig == true);
}
static void dbg_clear_trigger_flag(void)
{
	if (!g_force_trig && unlink(NCU_DBG_TRIGGER_FILE) != 0)
		IMP_LOG_ERR(TAG, "remove %s failed", NCU_DBG_TRIGGER_FILE);

	g_force_trig = false;
}

#ifdef NCU_PARAMS_DEBUG
static void init_default_ncu_params(NCUParams *ncu_params)
{
	if (ncu_params == NULL)
		return;

	ncu_params->dump_params = 1;
	ncu_params->ori_width = 1920;
	ncu_params->ori_height = 1080;
	ncu_params->ncu_tdns_en = 1;
	ncu_params->ncu_sdns_en = 1;
	ncu_params->ncu_sdns_en_ds = 0;
	ncu_params->ncu_shrp_en = 0;
	ncu_params->ncu_sdns_mv_use_en = 1;

	ncu_params->ncu_tdns_abs_mode = 2;
	ncu_params->ncu_tdns_strength = 900;
	ncu_params->ncu_tdns_min_thres = 300;
	ncu_params->ncu_tdns_peak_adjust = 0;
	ncu_params->ncu_tdns_slope = 160;
	ncu_params->ncu_psn_number = 2;
	ncu_params->ncu_psn_incr_stre = 0;
	ncu_params->ncu_psn_incr_stre_max = 300;
	ncu_params->ncu_psn_stre_max = 800;

	ncu_params->ncu_sdns_mv_thres = 300;
	ncu_params->ncu_sdns_mv_thres_ds = 300;

	ncu_params->ncu_sdns_smo_mo_min_thres = 250;
	ncu_params->ncu_sdns_tex_mo_min_thres = 250;
	ncu_params->ncu_sdns_smo_mo_min_thres_ds = 250;
	ncu_params->ncu_sdns_tex_mo_min_thres_ds = 250;

	ncu_params->ncu_sdns_hv_thres = 5;
	ncu_params->ncu_sdns_hv_thres_ds = 5;
	ncu_params->ncu_sdns_hv_ratio = 30;
	ncu_params->ncu_sdns_aa_thres = 3;
	ncu_params->ncu_sdns_edge_calc_abs_mode = 1;
	ncu_params->ncu_sdns_edge_calc_window = 1;
	ncu_params->ncu_sdns_edge_cmp_mode = 1;

	ncu_params->ncu_sdns_smo_central_en = 1;
	ncu_params->ncu_sdns_smo_window = 1;
	ncu_params->ncu_sdns_smo_strength = 0;
	ncu_params->ncu_sdns_smo_min_thres = 0;
	ncu_params->ncu_sdns_smo_peak_adjust = 0;
	ncu_params->ncu_sdns_smo_slope = 0;

	ncu_params->ncu_sdns_tex_central_en = 1;
	ncu_params->ncu_sdns_tex_window = 1;
	ncu_params->ncu_sdns_tex_use_edge = 0;
	ncu_params->ncu_sdns_tex_strength = 0;
	ncu_params->ncu_sdns_tex_min_thres = 0;
	ncu_params->ncu_sdns_tex_peak_adjust = 0;
	ncu_params->ncu_sdns_tex_slope = 0;

	ncu_params->ncu_sdns_smo_mo_central_en = 1;
	ncu_params->ncu_sdns_smo_mo_window = 1;
	ncu_params->ncu_sdns_smo_mo_strength = 1000;
	ncu_params->ncu_sdns_smo_mo_peak_adjust = 0;
	ncu_params->ncu_sdns_smo_mo_slope = 20;

	ncu_params->ncu_sdns_tex_mo_central_en = 1;
	ncu_params->ncu_sdns_tex_mo_window = 1;
	ncu_params->ncu_sdns_tex_mo_use_edge = 0;
	ncu_params->ncu_sdns_tex_mo_strength = 1000;
	ncu_params->ncu_sdns_tex_mo_peak_adjust = 0;
	ncu_params->ncu_sdns_tex_mo_slope = 30;

	ncu_params->lum_calc_window = 1;
	ncu_params->ncu_dk_y_thres = 0;
	ncu_params->ncu_br_y_thres = 255;

	ncu_params->ncu_dk_tdns_strength = 900;
	ncu_params->ncu_dk_tdns_min_thres = 5;
	ncu_params->ncu_dk_tdns_peak_adjust = 0;
	ncu_params->ncu_dk_tdns_slope = 40;

	ncu_params->ncu_br_tdns_strength = 900;
	ncu_params->ncu_br_tdns_min_thres = 5;
	ncu_params->ncu_br_tdns_peak_adjust = 0;
	ncu_params->ncu_br_tdns_slope = 40;

	ncu_params->ncu_sdns_dk_hv_thres = 4;
	ncu_params->ncu_sdns_dk_hv_thres_step = 0;
	ncu_params->ncu_sdns_dk_hv_thres_dir = 0;
	ncu_params->ncu_sdns_dk_aa_thres = 2;
	ncu_params->ncu_sdns_dk_aa_thres_step = 0;
	ncu_params->ncu_sdns_dk_aa_thres_dir = 0;
	ncu_params->ncu_sdns_dk_window = 1;
	ncu_params->ncu_sdns_dk_strength = 1000;
	ncu_params->ncu_sdns_dk_min_thres = 3;
	ncu_params->ncu_sdns_dk_thres_step = 0;
	ncu_params->ncu_sdns_dk_thres_dir = 0;
	ncu_params->ncu_sdns_dk_peak_adjust = 0;
	ncu_params->ncu_sdns_dk_slope = 20;

	ncu_params->ncu_sdns_br_hv_thres = 6;
	ncu_params->ncu_sdns_br_hv_thres_step = 0;
	ncu_params->ncu_sdns_br_hv_thres_dir =0;
	ncu_params->ncu_sdns_br_aa_thres = 3;
	ncu_params->ncu_sdns_br_aa_thres_step = 0;
	ncu_params->ncu_sdns_br_aa_thres_dir = 0;
	ncu_params->ncu_sdns_br_window = 1;
	ncu_params->ncu_sdns_br_strength = 1000;
	ncu_params->ncu_sdns_br_min_thres = 4;
	ncu_params->ncu_sdns_br_thres_step = 0;
	ncu_params->ncu_sdns_br_thres_dir = 0;
	ncu_params->ncu_sdns_br_peak_adjust = 0;
	ncu_params->ncu_sdns_br_slope = 10;

	ncu_params->ncu_shrp_mode = 0;
	ncu_params->ncu_shrp_mask_mode = 0;
	ncu_params->ncu_shrp_window = 1;
	ncu_params->ncu_shrp_high_stre = 100;
	ncu_params->ncu_shrp_low_stre = 100;
	ncu_params->ncu_shrp_alias_high_stre = 100;
	ncu_params->ncu_shrp_alias_low_stre = 100;
	ncu_params->ncu_shrp_high_roof = 100;
	ncu_params->ncu_shrp_low_roof = 100;

	ncu_params->ncu_dk_shrp_stre = 10;

	ncu_params->ncu_br_shrp_stre = 20;

	ncu_params->ncu_low_cut = 0;
	ncu_params->ncu_high_cut = 255;

	ncu_params->block_h_size = 64;
	ncu_params->block_w_size = 64;
	ncu_params->block_h_size_ds = 64;
	ncu_params->block_w_size_ds = 64;
	ncu_params->skip_h_size = 16;
	ncu_params->skip_w_size = 16;
	ncu_params->skip_h_size_ds = 16;
	ncu_params->skip_w_size_ds = 16;
	ncu_params->blur_radius_size = 8;
	ncu_params->blur_radius_size_ds = 8;
	ncu_params->blur_diff_thres = 9;
	ncu_params->blur_diff_thres_change_ds = 9;
	ncu_params->diff_num_thres = 2;
	ncu_params->pixel_blur_diff_thres = 2;
	ncu_params->mv_block_limit = 2;
	ncu_params->mv_block_limit_ds = 2;

	ncu_params->gain_threshold_0 = 0;
	ncu_params->gain_threshold_1 = 0;
	ncu_params->gain_threshold_2 = 0;
	ncu_params->gain_threshold_3 = 0;
	ncu_params->gain_threshold_4 = 0;
	ncu_params->gain_threshold_5 = 0;
	ncu_params->gain_threshold_6 = 0;
	ncu_params->gain_threshold_7 = 0;

#define DEFAULT_GAIN_GROUP_PARAMS(X)				\
	ncu_params->ncu_tdns_min_thres_##X = 0;			\
	ncu_params->ncu_tdns_strength_##X = 0;			\
	ncu_params->ncu_tdns_peak_adjust_##X = 0;		\
	ncu_params->ncu_psn_incr_stre_max_##X = 0;		\
	ncu_params->ncu_sdns_hv_thres_##X = 0;			\
	ncu_params->ncu_sdns_mv_thres_##X = 0;			\
	ncu_params->ncu_sdns_smo_mo_min_thres_##X = 0;	\
	ncu_params->ncu_sdns_tex_mo_min_thres_##X = 0;	\
	ncu_params->ncu_sdns_hv_thres_ds_##X = 0;			\
	ncu_params->ncu_sdns_mv_thres_ds_##X = 0;			\
	ncu_params->ncu_sdns_smo_mo_min_thres_ds_##X = 0;		\
	ncu_params->ncu_sdns_tex_mo_min_thres_ds_##X = 0;		\
	ncu_params->blur_diff_thres_##X = 0;			\
	ncu_params->pixel_blur_diff_thres_##X = 0;			\
	ncu_params->diff_num_thres_##X = 0

	DEFAULT_GAIN_GROUP_PARAMS(0);
	DEFAULT_GAIN_GROUP_PARAMS(1);
	DEFAULT_GAIN_GROUP_PARAMS(2);
	DEFAULT_GAIN_GROUP_PARAMS(3);
	DEFAULT_GAIN_GROUP_PARAMS(4);
	DEFAULT_GAIN_GROUP_PARAMS(5);
	DEFAULT_GAIN_GROUP_PARAMS(6);
	DEFAULT_GAIN_GROUP_PARAMS(7);
}
#endif

static void dump_ncu_params(NCUParams *ncu_params)
{
    if (access("/tmp/nodumpncu", F_OK) == 0) {
        return;
    }
	IMP_LOG_INFO(TAG, "dump_params = %d\n", ncu_params->dump_params);
	IMP_LOG_INFO(TAG, "ori_width = %d\n", ncu_params->ori_width);
	IMP_LOG_INFO(TAG, "ori_height = %d\n", ncu_params->ori_height);
	IMP_LOG_INFO(TAG, "ncu_tdns_en = %d\n", ncu_params->ncu_tdns_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_en = %d\n", ncu_params->ncu_sdns_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_en_ds = %d\n", ncu_params->ncu_sdns_en_ds);
	IMP_LOG_INFO(TAG, "ncu_shrp_en = %d\n", ncu_params->ncu_shrp_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_mv_use_en = %d\n", ncu_params->ncu_sdns_mv_use_en);
	IMP_LOG_INFO(TAG, "ncu_tdns_abs_mode = %d\n", ncu_params->ncu_tdns_abs_mode);
	IMP_LOG_INFO(TAG, "ncu_tdns_strength = %d\n", ncu_params->ncu_tdns_strength);
	IMP_LOG_INFO(TAG, "ncu_tdns_min_thres = %d\n", ncu_params->ncu_tdns_min_thres);
	IMP_LOG_INFO(TAG, "ncu_tdns_peak_adjust = %d\n", ncu_params->ncu_tdns_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_tdns_slope = %d\n", ncu_params->ncu_tdns_slope);
	IMP_LOG_INFO(TAG, "ncu_psn_number = %d\n", ncu_params->ncu_psn_number);
	IMP_LOG_INFO(TAG, "ncu_psn_incr_stre = %d\n", ncu_params->ncu_psn_incr_stre);
	IMP_LOG_INFO(TAG, "ncu_psn_incr_stre_max = %d\n", ncu_params->ncu_psn_incr_stre_max);
	IMP_LOG_INFO(TAG, "ncu_psn_stre_max = %d\n", ncu_params->ncu_psn_stre_max);
	IMP_LOG_INFO(TAG, "ncu_sdns_mv_thres = %d\n", ncu_params->ncu_sdns_mv_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_min_thres = %d\n", ncu_params->ncu_sdns_smo_mo_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_min_thres = %d\n", ncu_params->ncu_sdns_tex_mo_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_hv_thres = %d\n", ncu_params->ncu_sdns_hv_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_mv_thres_ds = %d\n", ncu_params->ncu_sdns_mv_thres_ds);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_min_thres_ds = %d\n", ncu_params->ncu_sdns_smo_mo_min_thres_ds);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_min_thres_ds = %d\n", ncu_params->ncu_sdns_tex_mo_min_thres_ds);
	IMP_LOG_INFO(TAG, "ncu_sdns_hv_thres_ds = %d\n", ncu_params->ncu_sdns_hv_thres_ds);
	IMP_LOG_INFO(TAG, "ncu_sdns_hv_ratio = %d\n", ncu_params->ncu_sdns_hv_ratio);
	IMP_LOG_INFO(TAG, "ncu_sdns_aa_thres = %d\n", ncu_params->ncu_sdns_aa_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_edge_calc_abs_mode = %d\n", ncu_params->ncu_sdns_edge_calc_abs_mode);
	IMP_LOG_INFO(TAG, "ncu_sdns_edge_calc_window = %d\n", ncu_params->ncu_sdns_edge_calc_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_edge_cmp_mode = %d\n", ncu_params->ncu_sdns_edge_cmp_mode);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_central_en = %d\n", ncu_params->ncu_sdns_smo_central_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_window = %d\n", ncu_params->ncu_sdns_smo_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_strength = %d\n", ncu_params->ncu_sdns_smo_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_min_thres = %d\n", ncu_params->ncu_sdns_smo_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_peak_adjust = %d\n", ncu_params->ncu_sdns_smo_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_slope = %d\n", ncu_params->ncu_sdns_smo_slope);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_central_en = %d\n", ncu_params->ncu_sdns_tex_central_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_window = %d\n", ncu_params->ncu_sdns_tex_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_use_edge = %d\n", ncu_params->ncu_sdns_tex_use_edge);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_strength = %d\n", ncu_params->ncu_sdns_tex_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_min_thres = %d\n", ncu_params->ncu_sdns_tex_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_peak_adjust = %d\n", ncu_params->ncu_sdns_tex_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_slope = %d\n", ncu_params->ncu_sdns_tex_slope);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_central_en = %d\n", ncu_params->ncu_sdns_smo_mo_central_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_window = %d\n", ncu_params->ncu_sdns_smo_mo_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_strength = %d\n", ncu_params->ncu_sdns_smo_mo_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_peak_adjust = %d\n", ncu_params->ncu_sdns_smo_mo_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_slope = %d\n", ncu_params->ncu_sdns_smo_mo_slope);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_central_en = %d\n", ncu_params->ncu_sdns_tex_mo_central_en);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_window = %d\n", ncu_params->ncu_sdns_tex_mo_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_use_edge = %d\n", ncu_params->ncu_sdns_tex_mo_use_edge);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_strength = %d\n", ncu_params->ncu_sdns_tex_mo_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_peak_adjust = %d\n", ncu_params->ncu_sdns_tex_mo_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_slope = %d\n", ncu_params->ncu_sdns_tex_mo_slope);
	IMP_LOG_INFO(TAG, "lum_calc_window = %d\n", ncu_params->lum_calc_window);
	IMP_LOG_INFO(TAG, "ncu_dk_y_thres = %d\n", ncu_params->ncu_dk_y_thres);
	IMP_LOG_INFO(TAG, "ncu_br_y_thres = %d\n", ncu_params->ncu_br_y_thres);
	IMP_LOG_INFO(TAG, "ncu_dk_tdns_strength = %d\n", ncu_params->ncu_dk_tdns_strength);
	IMP_LOG_INFO(TAG, "ncu_dk_tdns_min_thres = %d\n", ncu_params->ncu_dk_tdns_min_thres);
	IMP_LOG_INFO(TAG, "ncu_dk_tdns_peak_adjust = %d\n", ncu_params->ncu_dk_tdns_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_dk_tdns_slope = %d\n", ncu_params->ncu_dk_tdns_slope);
	IMP_LOG_INFO(TAG, "ncu_br_tdns_strength = %d\n", ncu_params->ncu_br_tdns_strength);
	IMP_LOG_INFO(TAG, "ncu_br_tdns_min_thres = %d\n", ncu_params->ncu_br_tdns_min_thres);
	IMP_LOG_INFO(TAG, "ncu_br_tdns_peak_adjust = %d\n", ncu_params->ncu_br_tdns_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_br_tdns_slope = %d\n", ncu_params->ncu_br_tdns_slope);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_hv_thres = %d\n", ncu_params->ncu_sdns_dk_hv_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_hv_thres_step = %d\n", ncu_params->ncu_sdns_dk_hv_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_hv_thres_dir = %d\n", ncu_params->ncu_sdns_dk_hv_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_aa_thres = %d\n", ncu_params->ncu_sdns_dk_aa_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_aa_thres_step = %d\n", ncu_params->ncu_sdns_dk_aa_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_aa_thres_dir = %d\n", ncu_params->ncu_sdns_dk_aa_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_window = %d\n", ncu_params->ncu_sdns_dk_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_strength = %d\n", ncu_params->ncu_sdns_dk_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_min_thres = %d\n", ncu_params->ncu_sdns_dk_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_thres_step = %d\n", ncu_params->ncu_sdns_dk_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_thres_dir = %d\n", ncu_params->ncu_sdns_dk_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_peak_adjust = %d\n", ncu_params->ncu_sdns_dk_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_dk_slope = %d\n", ncu_params->ncu_sdns_dk_slope);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_hv_thres = %d\n", ncu_params->ncu_sdns_br_hv_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_hv_thres_step = %d\n", ncu_params->ncu_sdns_br_hv_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_hv_thres_dir = %d\n", ncu_params->ncu_sdns_br_hv_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_aa_thres = %d\n", ncu_params->ncu_sdns_br_aa_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_aa_thres_step = %d\n", ncu_params->ncu_sdns_br_aa_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_aa_thres_dir = %d\n", ncu_params->ncu_sdns_br_aa_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_window = %d\n", ncu_params->ncu_sdns_br_window);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_strength = %d\n", ncu_params->ncu_sdns_br_strength);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_min_thres = %d\n", ncu_params->ncu_sdns_br_min_thres);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_thres_step = %d\n", ncu_params->ncu_sdns_br_thres_step);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_thres_dir = %d\n", ncu_params->ncu_sdns_br_thres_dir);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_peak_adjust = %d\n", ncu_params->ncu_sdns_br_peak_adjust);
	IMP_LOG_INFO(TAG, "ncu_sdns_br_slope = %d\n", ncu_params->ncu_sdns_br_slope);
	IMP_LOG_INFO(TAG, "ncu_shrp_mode = %d\n", ncu_params->ncu_shrp_mode);
	IMP_LOG_INFO(TAG, "ncu_shrp_mask_mode = %d\n", ncu_params->ncu_shrp_mask_mode);
	IMP_LOG_INFO(TAG, "ncu_shrp_window = %d\n", ncu_params->ncu_shrp_window);
	IMP_LOG_INFO(TAG, "ncu_shrp_high_stre = %d\n", ncu_params->ncu_shrp_high_stre);
	IMP_LOG_INFO(TAG, "ncu_shrp_low_stre = %d\n", ncu_params->ncu_shrp_low_stre);
	IMP_LOG_INFO(TAG, "ncu_shrp_alias_high_stre = %d\n", ncu_params->ncu_shrp_alias_high_stre);
	IMP_LOG_INFO(TAG, "ncu_shrp_alias_low_stre = %d\n", ncu_params->ncu_shrp_alias_low_stre);
	IMP_LOG_INFO(TAG, "ncu_shrp_high_roof = %d\n", ncu_params->ncu_shrp_high_roof);
	IMP_LOG_INFO(TAG, "ncu_shrp_low_roof = %d\n", ncu_params->ncu_shrp_low_roof);
	IMP_LOG_INFO(TAG, "ncu_dk_shrp_stre = %d\n", ncu_params->ncu_dk_shrp_stre);
	IMP_LOG_INFO(TAG, "ncu_br_shrp_stre = %d\n", ncu_params->ncu_br_shrp_stre);
	IMP_LOG_INFO(TAG, "ncu_low_cut = %d\n", ncu_params->ncu_low_cut);
	IMP_LOG_INFO(TAG, "ncu_high_cut = %d\n", ncu_params->ncu_high_cut);

	IMP_LOG_INFO(TAG, "block_h_size = %d\n", ncu_params->block_h_size);
	IMP_LOG_INFO(TAG, "block_w_size = %d\n", ncu_params->block_w_size);
	IMP_LOG_INFO(TAG, "block_h_size_ds = %d\n", ncu_params->block_h_size_ds);
	IMP_LOG_INFO(TAG, "block_w_size_ds = %d\n", ncu_params->block_w_size_ds);
	IMP_LOG_INFO(TAG, "skip_h_size = %d\n", ncu_params->skip_h_size);
	IMP_LOG_INFO(TAG, "skip_w_size = %d\n", ncu_params->skip_w_size);
	IMP_LOG_INFO(TAG, "skip_h_size_ds = %d\n", ncu_params->skip_h_size_ds);
	IMP_LOG_INFO(TAG, "skip_w_size_ds = %d\n", ncu_params->skip_w_size_ds);
	IMP_LOG_INFO(TAG, "blur_radius_size = %d\n", ncu_params->blur_radius_size);
	IMP_LOG_INFO(TAG, "blur_radius_size_ds = %d\n", ncu_params->blur_radius_size_ds);
	IMP_LOG_INFO(TAG, "blur_diff_thres = %d\n", ncu_params->blur_diff_thres);
	IMP_LOG_INFO(TAG, "blur_diff_thres_change_ds = %d\n", ncu_params->blur_diff_thres_change_ds);
	IMP_LOG_INFO(TAG, "diff_num_thres = %d\n", ncu_params->diff_num_thres);
	IMP_LOG_INFO(TAG, "pixel_blur_diff_thres = %d\n", ncu_params->pixel_blur_diff_thres);
	IMP_LOG_INFO(TAG, "mv_block_limit = %d\n", ncu_params->mv_block_limit);
	IMP_LOG_INFO(TAG, "mv_block_limit_ds = %d\n", ncu_params->mv_block_limit_ds);

	IMP_LOG_INFO(TAG, "gain_threshold_0 = %d\n", ncu_params->gain_threshold_0);
	IMP_LOG_INFO(TAG, "gain_threshold_1 = %d\n", ncu_params->gain_threshold_1);
	IMP_LOG_INFO(TAG, "gain_threshold_2 = %d\n", ncu_params->gain_threshold_2);
	IMP_LOG_INFO(TAG, "gain_threshold_3 = %d\n", ncu_params->gain_threshold_3);
	IMP_LOG_INFO(TAG, "gain_threshold_4 = %d\n", ncu_params->gain_threshold_4);
	IMP_LOG_INFO(TAG, "gain_threshold_5 = %d\n", ncu_params->gain_threshold_5);
	IMP_LOG_INFO(TAG, "gain_threshold_6 = %d\n", ncu_params->gain_threshold_6);
	IMP_LOG_INFO(TAG, "gain_threshold_7 = %d\n", ncu_params->gain_threshold_7);

#define PRINT_GAIN_GROUP_PARAMS(X)										\
	IMP_LOG_INFO(TAG, "ncu_tdns_min_thres_%d = %d\n", X, ncu_params->ncu_tdns_min_thres_##X); \
	IMP_LOG_INFO(TAG, "ncu_tdns_strength_%d = %d\n", X, ncu_params->ncu_tdns_strength_##X); \
	IMP_LOG_INFO(TAG, "ncu_tdns_peak_adjust_%d = %d\n", X, ncu_params->ncu_tdns_peak_adjust_##X); \
	IMP_LOG_INFO(TAG, "ncu_psn_incr_stre_max_%d = %d\n", X, ncu_params->ncu_psn_incr_stre_max_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_hv_thres_%d = %d\n", X, ncu_params->ncu_sdns_hv_thres_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_mv_thres_%d = %d\n", X, ncu_params->ncu_sdns_mv_thres_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_min_thres_%d = %d\n", X, ncu_params->ncu_sdns_smo_mo_min_thres_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_min_thres_%d = %d\n", X, ncu_params->ncu_sdns_tex_mo_min_thres_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_hv_thres_ds_%d = %d\n", X, ncu_params->ncu_sdns_hv_thres_ds_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_mv_thres_ds_%d = %d\n", X, ncu_params->ncu_sdns_mv_thres_ds_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_smo_mo_min_thres_ds_%d = %d\n", X, ncu_params->ncu_sdns_smo_mo_min_thres_ds_##X); \
	IMP_LOG_INFO(TAG, "ncu_sdns_tex_mo_min_thres_ds_%d = %d\n", X, ncu_params->ncu_sdns_tex_mo_min_thres_ds_##X); \
	IMP_LOG_INFO(TAG, "blur_diff_thres_%d = %d\n", X, ncu_params->blur_diff_thres_##X); \
	IMP_LOG_INFO(TAG, "diff_num_thres_%d = %d\n", X, ncu_params->diff_num_thres_##X); \
	IMP_LOG_INFO(TAG, "pixel_blur_diff_thres_%d = %d\n", X, ncu_params->pixel_blur_diff_thres_##X)

	PRINT_GAIN_GROUP_PARAMS(0);
	PRINT_GAIN_GROUP_PARAMS(1);
	PRINT_GAIN_GROUP_PARAMS(2);
	PRINT_GAIN_GROUP_PARAMS(3);
	PRINT_GAIN_GROUP_PARAMS(4);
	PRINT_GAIN_GROUP_PARAMS(5);
	PRINT_GAIN_GROUP_PARAMS(6);
	PRINT_GAIN_GROUP_PARAMS(7);
}

static int load_ncu_params_from_buffer(void *buf, int len, NCUParams *ncu_params)
{
	NCUParams *p;
	p = ncuparams__unpack(NULL, len, (const uint8_t*)buf);

	if (p) {
		/* Get it. */
		memcpy(ncu_params, p, sizeof(NCUParams));
		if (p->dump_params)
			dump_ncu_params(p);

		ncuparams__free_unpacked(p, NULL);

		return 0;
	}
	IMP_LOG_ERR(TAG, "unpack nd params failed");

	return -1;
}

static int load_ncu_params_from_file(int fd, NCUParams *ncu_params)
{
	void *tmp_buf = malloc(TMP_BUF_SIZE);
	if (tmp_buf == NULL) {
		IMP_LOG_ERR(TAG, "malloc tmp buf failed:%s", strerror(errno));
		return -1;
	}

	int ret = 0, len;
	len = read(fd, tmp_buf, TMP_BUF_SIZE);
	if (len <= 0) {
		IMP_LOG_ERR(TAG, "read nd.bin failed:%s", strerror(errno));
		ret = -1;
		goto _exit;
	}

	if (load_ncu_params_from_buffer(tmp_buf, len, ncu_params) < 0) {
		IMP_LOG_ERR(TAG, "load nd.bin failed");
		ret = -1;
		goto _exit;
	}

	g_ncu_availiable = true;
_exit:
	free(tmp_buf);
	return ret;
}

int refresh_ncu_params(uint32_t total_gain)
{
	int dbg_trig = 0;
	if (g_ncu_params_p == NULL)
		return -1;
	dbg_trig = dbg_is_triggered();
	if (g_debug_mode_en && dbg_trig) { /* Debug mode. */
		int fd = open(NCU_DBG_CONFIG_FILE, O_RDONLY);
		if (fd < 0) {
			IMP_LOG_ERR(TAG, "open %s failed: %s", NCU_DBG_CONFIG_FILE, strerror(errno));
			return -1;
		}

		load_ncu_params_from_file(fd, g_ncu_params_p);

		close(fd);
		dbg_clear_trigger_flag();
	}

	if (g_ncu_availiable == false) /* No params loaded. */
		return 0;

#define XXX(X, X_1, Y_1, X_2, Y_2) ((X * Y_2 + X_1 * Y_1 + X_2 * Y_1 - X_1 * Y_2 - X * Y_1 - X_1 * Y_1) / (X_2 - X_1))
#define YYY(L, R)														\
	p->ncu_tdns_min_thres = XXX(total_gain, p->gain_threshold_##L, p->ncu_tdns_min_thres_##L, p->gain_threshold_##R, p->ncu_tdns_min_thres_##R); \
	p->ncu_tdns_strength = XXX(total_gain, p->gain_threshold_##L, p->ncu_tdns_strength_##L, p->gain_threshold_##R, p->ncu_tdns_strength_##R); \
	p->ncu_tdns_peak_adjust = XXX(total_gain, p->gain_threshold_##L, p->ncu_tdns_peak_adjust_##L, p->gain_threshold_##R, p->ncu_tdns_peak_adjust_##R); \
	p->ncu_psn_incr_stre_max = XXX(total_gain, p->gain_threshold_##L, p->ncu_psn_incr_stre_max_##L, p->gain_threshold_##R, p->ncu_psn_incr_stre_max_##R); \
	p->ncu_sdns_hv_thres = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_hv_thres_##L, p->gain_threshold_##R, p->ncu_sdns_hv_thres_##R); \
	p->ncu_sdns_mv_thres = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_mv_thres_##L, p->gain_threshold_##R, p->ncu_sdns_mv_thres_##R); \
	p->ncu_sdns_smo_mo_min_thres = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_smo_mo_min_thres_##L, p->gain_threshold_##R, p->ncu_sdns_smo_mo_min_thres_##R); \
	p->ncu_sdns_tex_mo_min_thres = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_tex_mo_min_thres_##L, p->gain_threshold_##R, p->ncu_sdns_tex_mo_min_thres_##R); \
	p->ncu_sdns_hv_thres_ds = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_hv_thres_ds_##L, p->gain_threshold_##R, p->ncu_sdns_hv_thres_ds_##R); \
	p->ncu_sdns_mv_thres_ds = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_mv_thres_ds_##L, p->gain_threshold_##R, p->ncu_sdns_mv_thres_ds_##R); \
	p->ncu_sdns_smo_mo_min_thres_ds = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_smo_mo_min_thres_ds_##L, p->gain_threshold_##R, p->ncu_sdns_smo_mo_min_thres_ds_##R); \
	p->ncu_sdns_tex_mo_min_thres_ds = XXX(total_gain, p->gain_threshold_##L, p->ncu_sdns_tex_mo_min_thres_ds_##L, p->gain_threshold_##R, p->ncu_sdns_tex_mo_min_thres_ds_##R); \
	p->blur_diff_thres = XXX(total_gain, p->gain_threshold_##L, p->blur_diff_thres_##L, p->gain_threshold_##R, p->blur_diff_thres_##R); \
	p->diff_num_thres = XXX(total_gain, p->gain_threshold_##L, p->diff_num_thres_##L, p->gain_threshold_##R, p->diff_num_thres_##R); \
	p->pixel_blur_diff_thres = XXX(total_gain, p->gain_threshold_##L, p->pixel_blur_diff_thres_##L, p->gain_threshold_##R, p->pixel_blur_diff_thres_##R)

	NCUParams *p = g_ncu_params_p;
	if ((total_gain != g_last_total_gain) || dbg_trig) {
		if (total_gain <= p->gain_threshold_0) {
			p->ncu_tdns_min_thres = p->ncu_tdns_min_thres_0;
			p->ncu_tdns_strength = p->ncu_tdns_strength_0;
			p->ncu_tdns_peak_adjust = p->ncu_tdns_peak_adjust_0;
			p->ncu_psn_incr_stre_max = p->ncu_psn_incr_stre_max_0;
			p->ncu_sdns_hv_thres = p->ncu_sdns_hv_thres_0;
			p->ncu_sdns_mv_thres = p->ncu_sdns_mv_thres_0;
			p->ncu_sdns_smo_mo_min_thres = p->ncu_sdns_smo_mo_min_thres_0;
			p->ncu_sdns_tex_mo_min_thres = p->ncu_sdns_tex_mo_min_thres_0;
			p->ncu_sdns_hv_thres_ds = p->ncu_sdns_hv_thres_ds_0;
			p->ncu_sdns_mv_thres_ds = p->ncu_sdns_mv_thres_ds_0;
			p->ncu_sdns_smo_mo_min_thres_ds = p->ncu_sdns_smo_mo_min_thres_ds_0;
			p->ncu_sdns_tex_mo_min_thres_ds = p->ncu_sdns_tex_mo_min_thres_ds_0;
			p->blur_diff_thres = p->blur_diff_thres_0;
			p->diff_num_thres = p->diff_num_thres_0;
			p->pixel_blur_diff_thres = p->pixel_blur_diff_thres_0;
		} else if (total_gain > p->gain_threshold_0 && total_gain <= p->gain_threshold_1) {
			YYY(0, 1);
		} else if (total_gain > p->gain_threshold_1 && total_gain <= p->gain_threshold_2) {
			YYY(1, 2);
		} else if (total_gain > p->gain_threshold_2 && total_gain <= p->gain_threshold_3) {
			YYY(2, 3);
		} else if (total_gain > p->gain_threshold_3 && total_gain <= p->gain_threshold_4) {
			YYY(3, 4);
		} else if (total_gain > p->gain_threshold_4 && total_gain <= p->gain_threshold_5) {
			YYY(4, 5);
		} else if (total_gain > p->gain_threshold_5 && total_gain <= p->gain_threshold_6) {
			YYY(5, 6);
		} else if (total_gain > p->gain_threshold_6 && total_gain <= p->gain_threshold_7) {
			YYY(6, 7);
		} else if (p->gain_threshold_7 && (total_gain > p->gain_threshold_7)) {
			p->ncu_tdns_min_thres = p->ncu_tdns_min_thres_7;
			p->ncu_tdns_strength = p->ncu_tdns_strength_7;
			p->ncu_tdns_peak_adjust = p->ncu_tdns_peak_adjust_7;
			p->ncu_psn_incr_stre_max = p->ncu_psn_incr_stre_max_7;
			p->ncu_sdns_hv_thres = p->ncu_sdns_hv_thres_7;
			p->ncu_sdns_mv_thres = p->ncu_sdns_mv_thres_7;
			p->ncu_sdns_smo_mo_min_thres = p->ncu_sdns_smo_mo_min_thres_7;
			p->ncu_sdns_tex_mo_min_thres = p->ncu_sdns_tex_mo_min_thres_7;
			p->ncu_sdns_hv_thres_ds = p->ncu_sdns_hv_thres_ds_7;
			p->ncu_sdns_mv_thres_ds = p->ncu_sdns_mv_thres_ds_7;
			p->ncu_sdns_smo_mo_min_thres_ds = p->ncu_sdns_smo_mo_min_thres_ds_7;
			p->ncu_sdns_tex_mo_min_thres_ds = p->ncu_sdns_tex_mo_min_thres_ds_7;
			p->blur_diff_thres = p->blur_diff_thres_7;
			p->diff_num_thres = p->diff_num_thres_7;
			p->pixel_blur_diff_thres = p->pixel_blur_diff_thres_7;
		}
	}

	if ((access("/tmp/nodumpncu", F_OK) != 0) && g_ncu_params_p->dump_params && ((total_gain != g_last_total_gain) || dbg_trig)) {
		IMP_LOG_DBG(TAG, "###############");
		IMP_LOG_DBG(TAG, "current total gain = %d", total_gain);
		IMP_LOG_DBG(TAG, "ncu_tdns_min_thres = %d", g_ncu_params_p->ncu_tdns_min_thres);
		IMP_LOG_DBG(TAG, "ncu_tdns_strength = %d", g_ncu_params_p->ncu_tdns_strength);
		IMP_LOG_DBG(TAG, "ncu_tdns_peak_adjust = %d", g_ncu_params_p->ncu_tdns_peak_adjust);
		IMP_LOG_DBG(TAG, "ncu_psn_incr_stre_max = %d", g_ncu_params_p->ncu_psn_incr_stre_max);
		IMP_LOG_DBG(TAG, "ncu_sdns_hv_thres = %d", g_ncu_params_p->ncu_sdns_hv_thres);
		IMP_LOG_DBG(TAG, "ncu_sdns_mv_thres = %d", g_ncu_params_p->ncu_sdns_mv_thres);
		IMP_LOG_DBG(TAG, "ncu_sdns_smo_mo_min_thres = %d", g_ncu_params_p->ncu_sdns_smo_mo_min_thres);
		IMP_LOG_DBG(TAG, "ncu_sdns_tex_mo_min_thres = %d", g_ncu_params_p->ncu_sdns_tex_mo_min_thres);
		IMP_LOG_DBG(TAG, "ncu_sdns_hv_thres_ds = %d", g_ncu_params_p->ncu_sdns_hv_thres_ds);
		IMP_LOG_DBG(TAG, "ncu_sdns_mv_thres_ds = %d", g_ncu_params_p->ncu_sdns_mv_thres_ds);
		IMP_LOG_DBG(TAG, "ncu_sdns_smo_mo_min_thres_ds = %d", g_ncu_params_p->ncu_sdns_smo_mo_min_thres_ds);
		IMP_LOG_DBG(TAG, "ncu_sdns_tex_mo_min_thres_ds = %d", g_ncu_params_p->ncu_sdns_tex_mo_min_thres_ds);
		IMP_LOG_DBG(TAG, "blur_diff_thres = %d", g_ncu_params_p->blur_diff_thres);
		IMP_LOG_DBG(TAG, "diff_num_thres = %d", g_ncu_params_p->diff_num_thres);
		IMP_LOG_DBG(TAG, "pixel_blur_diff_thres = %d", g_ncu_params_p->pixel_blur_diff_thres);
		IMP_LOG_DBG(TAG, "--------------");
		IMP_LOG_DBG(TAG, "ncu_psn_number  = %d", g_ncu_params_p->ncu_psn_number   );
		IMP_LOG_DBG(TAG, "ncu_psn_incr_stre  = %d", g_ncu_params_p->ncu_psn_incr_stre);
		IMP_LOG_DBG(TAG, "ncu_psn_stre_max  = %d", g_ncu_params_p->ncu_psn_stre_max );
		IMP_LOG_DBG(TAG, "block_h_size =  %d", g_ncu_params_p->block_h_size);
		IMP_LOG_DBG(TAG, "block_w_size  = %d", g_ncu_params_p->block_w_size);
		IMP_LOG_DBG(TAG, "block_h_size_ds  = %d", g_ncu_params_p->block_h_size_ds);
		IMP_LOG_DBG(TAG, "block_w_size_ds  = %d", g_ncu_params_p->block_w_size_ds);
		IMP_LOG_DBG(TAG, "skip_h_size_ds  = %d", g_ncu_params_p->skip_h_size_ds);
		IMP_LOG_DBG(TAG, "skip_w_size_ds  = %d", g_ncu_params_p->skip_w_size_ds);
		IMP_LOG_DBG(TAG, "blur_radius_size  = %d", g_ncu_params_p->blur_radius_size);
		IMP_LOG_DBG(TAG, "blur_radius_size_ds  = %d", g_ncu_params_p->blur_radius_size_ds);
		IMP_LOG_DBG(TAG, "blur_diff_thres_change_ds  = %d", g_ncu_params_p->blur_diff_thres_change_ds);
	}
	g_last_total_gain = total_gain;

	return 0;
}

int init_ncu_params(const char *sensor_name)
{
	if (g_ncu_params_p) {
		IMP_LOG_ERR(TAG, "ncu params already init");
		return 0;
	}

	if (access(NCU_DBG_ENABLE_FILE, F_OK) == 0)
		g_debug_mode_en = true;

	IMP_LOG_INFO(TAG, "NCU Debug mode:%d", g_debug_mode_en);

	g_ncu_params_p = malloc(sizeof(NCUParams));
	if (g_ncu_params_p == NULL) {
		IMP_LOG_ERR(TAG, "Failed to malloc NCUParams:%s", strerror(errno));
		return -1;
	}

#ifndef NCU_PARAMS_DEBUG
	if (g_debug_mode_en) {
		g_force_trig = true;
		refresh_ncu_params(0);
	} else {
		char cfg_file_path[64];
		if (sensor_name)
			snprintf(cfg_file_path, 64, "%s%s_nd.bin",
					 NCU_CONFIG_FILE_PATH_PREFIX, sensor_name);

		int fd = open(cfg_file_path, O_RDONLY);
		if (fd < 0) {
			IMP_LOG_ERR(TAG, "open %s failed: %s", cfg_file_path, strerror(errno));
			return -1;
		}

		NCUParams ncu_params_tmp;
		if (load_ncu_params_from_file(fd, &ncu_params_tmp) < 0) {
			IMP_LOG_ERR(TAG, "load param failed");
			close(fd);
			return -1;
		}

		memcpy(g_ncu_params_p, &ncu_params_tmp, sizeof(NCUParams));

		close(fd);
	}
	return 0;
#else
	init_default_ncu_params(g_ncu_params_p);
	return 0;
#endif
}
